package XMFramework.Core
{
	import XMFramework.Core.Internal.SDownloader;
	import XMFramework.Interface.IConfig;
	
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;

	internal class SConfig implements IConfig
	{
		private var jsonData : Array		=	new Array();	
		
		private var configMeta:Array;
		private var patchFileUrl:String;		
		private var configFileUrl:String;
		
		private var downloadJSONFile:Array	=	new Array();		
		private var onResultFunc:Function;
		private var onStepLoadFunc:Function;
		
		internal var totalBytes:int			=	0;
		internal var loadedBytes:int		=	0;
		
		public function getMetadata( name : String ) : Object
		{
			for( var i : String in jsonData )
				if( jsonData[i].hasOwnProperty( name ) )
					return jsonData[i][name];
			
			return null;
		}
		
		public function loadSWF( url:String, configMetaList:Array, onResult:Function, onStepLoad:Function ) : void
		{
			onResultFunc	=	onResult;
			onStepLoadFunc	=	onStepLoad;
				
			configMeta		=	configMetaList;			
			configFileUrl	=	url;
			downloadSWF( configFileUrl, onLoadSWFSuccess, onLoadSWFError, onStepLoad );
		}
		
		public function loadJSON( identityUrls : Array, onResult : Function ) : void
		{
			onResultFunc		=	onResult;
			
			var downloader:SDownloader;
			for each( var url:String in identityUrls )
			{
				var inProgress:Boolean	=	false;
				for( var i:String in downloadJSONFile )
				{
					if( downloadJSONFile[i].URL == url )
					{
						inProgress	=	true;
						break;
					}
				}
				
				if( inProgress == false )
				{
					downloader	=	new SDownloader( url );
					downloader.download( onLoadJSONSuccess );
					downloadJSONFile.push( downloader );
				}
			}
		}
		
		public function loadPatchFile( url:String, onResult:Function, onStepLoad:Function ):void
		{
			onResultFunc	=	onResult;
			onStepLoadFunc	=	onStepLoad;
			
			patchFileUrl	=	url;
			var downloader:SDownloader	=	new SDownloader( url );
			downloader.download( onLoadPatchFileSuccess, onStepLoad );
			
			function onLoadPatchFileSuccess( event : Event ) : void
			{
				trace( "SCore::onLoadPatchFile succeeded" );
				
				var json : String		=	event.target.data;
				var dataBunch : Object	=	JSONPaser.deserialize( json );
				
				pushOverrideDataTag( dataBunch );
				
				onResultFunc.call( null, 1, "SConfig::loadPatchFile succeeded" );
			}
		}
		
		private function onLoadJSONSuccess( event : Event ) : void
		{
			var json : String		=	event.target.data;
			var dataBunch : Object	=	JSONPaser.deserialize( json );
			
			// Old code
			//jsonData.push( SCore.ObjectCopy( dataBunch ) );
			// Change to override pushing data
			pushOverrideDataTag( dataBunch );
			
			dataBunch	=	null;
			
			for( var i:String in downloadJSONFile )
				if( downloadJSONFile[i].isSuccess )
					downloadJSONFile.splice( i, 1 );
			
			// Download hasn't completed yet
			if( downloadJSONFile.length == 0 )
				onResultFunc.call( null, 0, "SConfig::onLoadJSONSuccess successded" );
		}
		
		private function onLoadSWFSuccess( evt:Event ) : void
		{			
			var moduleDomain:ApplicationDomain	=	evt.currentTarget.applicationDomain;
			var snsConfigClass:Class			=	moduleDomain.getDefinition( "SNSConfig" ) as Class;
			if( snsConfigClass == null )
				onResultFunc.call( null, -2, "SNSConfig Class definition not found" );
			
			var snsConfig:Object	=	new snsConfigClass;			
			for each( var name:String in configMeta )
			{
				var jsonStr:String		=	snsConfig.getData( name );
				if( jsonStr == "penguins" )
					var a:int  = 0;
				var dataBunch:Object	=	JSONPaser.deserialize( jsonStr );
				
				// Old code
				//jsonData.push( dataBunch );
				// Change to override pushing data
				pushOverrideDataTag( dataBunch );
			}
			
			onResultFunc.call( null, 0, "Download succeeded" );
		}
		
		private function onLoadSWFError( evt:IOErrorEvent ) : void
		{
			trace("SConfig::downloadSWF failed: " + evt.text);
			
			// Retry download swf file
			downloadSWF( configFileUrl, onLoadSWFSuccess, onLoadSWFError, onStepLoadFunc );
		}				
		
		private function downloadSWF( url:String, onComplete:Function, onFault:Function, onLoadPercentage:Function ) : void
		{			
			var context:LoaderContext	=	new LoaderContext();
			context.applicationDomain	=	ApplicationDomain.currentDomain;	// Loader's own ApplicationDomain
			context.securityDomain		=	null;
			
			var loader:Loader			=	new Loader();
			loader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, onFault, false, 0, true );
			
			var dispatcher : IEventDispatcher	=	loader.contentLoaderInfo;
			dispatcher.addEventListener( Event.COMPLETE, onComplete, false, 0, true );
			dispatcher.addEventListener( IOErrorEvent.IO_ERROR, onFault, false, 0, true );
			dispatcher.addEventListener( ProgressEvent.PROGRESS, onLoadPercentage, false, 0, true );
			
			loader.load( new URLRequest( url ), context );
			
			trace( "SConfig::downloadSWF started" );
		}
		
		private function pushOverrideDataTag( newData:Object ) : void
		{
			for( var tagNewIndex : String in newData )
			{
				for( var currJsonListIndex : String in jsonData )
				{
					for( var tagOldIndex : String in jsonData[currJsonListIndex] )
					{
						// Check exist tag name
						if( tagOldIndex == tagNewIndex )
						{
							var index : String
							
							// Start merge old data into new bucket data bundle
							var oldBundle : Object	=	jsonData[currJsonListIndex][tagOldIndex];
							
							// Push array
							var newDataPtr : Array	=	newData[tagNewIndex] as Array;
							if( newDataPtr != null ) // Is array
							{
								for( index in oldBundle )
									newDataPtr.push( oldBundle[index] );
							}
							
							// Or object
							else
							{
								for( index in oldBundle )
									newData[tagNewIndex][index]	=	oldBundle[index];
							}
							
							// Remove exist tag in old data
							delete jsonData[currJsonListIndex][tagOldIndex];
						}
					}
				}
			}
			
			// Append to old data array
			jsonData.push( newData );
		}
		
		///////////////////////////////////////////////////////
		//
		
		public function getEntityConf(entityID : String):Object
		{
			var entityConf : Object = getMetadata(ShareMacros.CONF_ENTITY);
			return entityConf[entityID];
		}
		
		public function getPropertyConf( PropertyID : String ):Object
		{
			var PropertyConf : Object = getMetadata(ShareMacros.CONF_PROPERTIES);
			return PropertyConf[PropertyID];
		}
		
		public function getPropertyConfFromEntity( entityID : String):Array
		{
			var entity : Object = getEntityConf(entityID);
			var arrPro : Array = new Array();
			for each( var proID : String in entity["properties"]["lv_1"] );
				arrPro.push( getPropertyConf(proID) );
			return arrPro;
		}
		
		public function getItemOrEntity(entityID : String):Object
		{
			var entityConf : Object = getMetadata(ShareMacros.CONF_ENTITY);
			if( entityConf.hasOwnProperty(entityID) )
				return entityConf[entityID];
			
			entityConf = getMetadata(ShareMacros.CONF_GAME_ITEMS);
			if( entityConf.hasOwnProperty(entityID) )
				return entityConf[entityID];
			
			return null;
		}
		
		public function getShopItemConf( id : String ):Object
		{
			var items : Object = getMetadata(ShareMacros.CONF_SHOP_ITEMS);
			if( items.hasOwnProperty(id) )
				return items[id];
			return null;
		}
		
		public function getItemConf( id : String ):Object
		{
			var items : Object = getMetadata(ShareMacros.CONF_GAME_ITEMS);
			if( items.hasOwnProperty(id) )
				return items[id];
			return null;
		}
		
		public function getRequireLvOfIcon( id : String ):int
		{
			var lvdata : Object = getMetadata(ShareMacros.CONF_REQUIRE_ICON_LV);
			return lvdata[id];
		}
	}
}